package ai.assist.common.businesss.service;

import ai.assist.common.businesss.mongo.entity.*;
import com.alibaba.fastjson.JSON;
import ai.assist.common.businesss.mongo.service.SysPermissionService;
import ai.assist.common.context.UserInfoContext;
import ai.assist.common.utils.PasswordEncoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author hui
 * @Date 2024/2/18 21:18
 **/
@Slf4j
@Service
public class UserSessionService {

    public static final String TICKET_PREFIX = "netgov:cgj:ticket:";

    public static final String LOGIN_TICKET_PREFIX = "netgov:cgj:ticketList:";

    @Value("${spring.application.expire:72000}")
    private long tokenExpire;

    @Autowired
    private MongoBeanUtil mongoBeanUtil;

    public String createTicket(UserInfoContext userInfoContext) {
        String ticket = UUID.randomUUID().toString().replace("-", "") + PasswordEncoder.hexMD5(userInfoContext.getId() + userInfoContext.getUsername() + userInfoContext.getPhone() + new Date().getTime());
        log.info("initTicket_getTicketKey:{}，{}", userInfoContext, ticket);
        String ssoKey = TICKET_PREFIX + ticket;
        String ssoIdKey = LOGIN_TICKET_PREFIX + userInfoContext.getId();
        mongoBeanUtil.getRedisTemplate().opsForValue().set(ssoKey, JSON.toJSONString(userInfoContext), tokenExpire, TimeUnit.SECONDS);
        String ticketsString = mongoBeanUtil.getRedisTemplate().opsForValue().get(ssoIdKey);
        List<String> tickets = new ArrayList<>();
        if (ticketsString != null && !StringUtils.isEmpty(ticketsString)) {
            tickets = JSON.parseArray(ticketsString, String.class);
        }
        tickets.add(ticket);
        mongoBeanUtil.getRedisTemplate().opsForValue().set(ssoIdKey, JSON.toJSONString(tickets), tokenExpire, TimeUnit.SECONDS);
        return ticket;
    }

    public String createTicket(String userId) {
        UserInfoContext userInfoContext = this.getUserContext(userId);
        return this.createTicket(userInfoContext);
    }

    public String reflashTicket(String userId, String ticket) {
        UserInfoContext userInfoContext = this.getUserContext(userId);
        String ssoKey = TICKET_PREFIX + ticket;
        String ssoIdKey = LOGIN_TICKET_PREFIX + userInfoContext.getId();
        mongoBeanUtil.getRedisTemplate().opsForValue().set(ssoKey, JSON.toJSONString(userInfoContext), tokenExpire, TimeUnit.SECONDS);
        String ticketsString = mongoBeanUtil.getRedisTemplate().opsForValue().get(ssoIdKey);
        List<String> tickets = new ArrayList<>();
        if (ticketsString != null && !StringUtils.isEmpty(ticketsString)) {
            tickets = JSON.parseArray(ticketsString, String.class);
        }
        tickets.add(ticket);
        mongoBeanUtil.getRedisTemplate().opsForValue().set(ssoIdKey, JSON.toJSONString(tickets), tokenExpire, TimeUnit.SECONDS);
        return ticket;
    }


    public void logout(String ticket) {
        //删除用户对应ticket
        String ssoKey = LOGIN_TICKET_PREFIX + ticket;
//        redisTemplate.delete(ssoKey);
        String user = mongoBeanUtil.getRedisTemplate().opsForValue().get(ssoKey);
        if (!StringUtils.isEmpty(user)) {
            UserInfoContext userInfo = JSON.parseObject(user, UserInfoContext.class);
            if (userInfo != null) {
                String ssoIdKey = TICKET_PREFIX + userInfo.getId();
                String ticketsString = mongoBeanUtil.getRedisTemplate().opsForValue().get(ssoIdKey);
                if (ticketsString != null && !StringUtils.isEmpty(ticketsString)) {
                    List<String> tickets = JSON.parseArray(ticketsString, String.class);
                    tickets.forEach(t -> mongoBeanUtil.getRedisTemplate().delete(TICKET_PREFIX + t));
                }
                mongoBeanUtil.getRedisTemplate().delete(ssoIdKey);
            }
            mongoBeanUtil.getRedisTemplate().delete(ssoKey);
        }
    }

    public UserInfoContext validateTicket(String ticket) {
        // 获取用户信息token
        String ssoKey = TICKET_PREFIX + ticket;
        String user = mongoBeanUtil.getRedisTemplate().opsForValue().get(ssoKey);
        if (!StringUtils.isEmpty(user)) {
            UserInfoContext userInfo = JSON.parseObject(user, UserInfoContext.class);
            if (userInfo != null) {
                //刷新过期时间
                mongoBeanUtil.getRedisTemplate().expire(ssoKey, tokenExpire, TimeUnit.SECONDS);
                String ssoIdKey = LOGIN_TICKET_PREFIX + userInfo.getId();
                mongoBeanUtil.getRedisTemplate().expire(ssoIdKey, tokenExpire, TimeUnit.SECONDS);
                return userInfo;
            }
        }
        return null;
//        throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "用户ticket无效！");
    }

    public void reflashTicket(String userId) {
        String ssoIdKey = LOGIN_TICKET_PREFIX + userId;
        String ssoKey = mongoBeanUtil.getRedisTemplate().opsForValue().get(ssoIdKey);
        if (StringUtils.isEmpty(ssoKey)) {
            return;
        }
        String user = mongoBeanUtil.getRedisTemplate().opsForValue().get(ssoKey);
        if (user != null && !StringUtils.isEmpty(user)) {
            List<String> tickets = JSON.parseArray(user, String.class);
            for (String ticket : tickets) {
                String userString = mongoBeanUtil.getRedisTemplate().opsForValue().get(TICKET_PREFIX + ticket);
                if (userString != null && !StringUtils.isEmpty(userString)) {
                    UserInfoContext userInfo = JSON.parseObject(userString, UserInfoContext.class);
                    userInfo = this.getUserContext(userInfo.getId());
                    mongoBeanUtil.getRedisTemplate().opsForValue().set(TICKET_PREFIX + ticket, JSON.toJSONString(userInfo), tokenExpire, TimeUnit.SECONDS);
                }
            }
        }
    }

    @Autowired
    private SysPermissionService sysPermissionService;

    public UserInfoContext getUserContext(String userId) {
        SysUser user = mongoBeanUtil.getUserService().lambdaQuery().eq(SysUser::getId, userId).limitOne();
        List<String> roles = mongoBeanUtil.getSysUserRoleService().lambdaQuery().eq(SysUserRole::getUserId, userId).list().stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
        List<String> permissionIds = mongoBeanUtil.getSysRolePermissionService().lambdaQuery().in(SysRolePermission::getRoleId, roles).list().stream().map(SysRolePermission::getPermissionId).collect(Collectors.toList());
        List<SysPermission> permissions = sysPermissionService.lambdaQuery().in(SysPermission::getId, permissionIds).list();
        SysDept dept = mongoBeanUtil.getDeptService().lambdaQuery().eq(SysDept::getId, user.getDeptId()).limitOne();
        UserInfoContext context = UserInfoContext.create(user, dept, roles, permissions);
        return context;
    }

    public void abortUserByUserIds(List<Long> userIds) {
        userIds.forEach(i -> {
            String ssoIdKey = LOGIN_TICKET_PREFIX + i;
            String ssoKey = mongoBeanUtil.getRedisTemplate().opsForValue().get(ssoIdKey);
            if (!StringUtils.isEmpty(ssoKey)) {
                List<String> tickets = JSON.parseArray(ssoKey, String.class);
                tickets.forEach(t -> mongoBeanUtil.getRedisTemplate().delete(TICKET_PREFIX + t));
                mongoBeanUtil.getRedisTemplate().delete(ssoKey);
            }
        });
    }

    public void abortUserByUserId(String userId) {
        String ssoIdKey = LOGIN_TICKET_PREFIX + userId;
        String ssoKey = mongoBeanUtil.getRedisTemplate().opsForValue().get(ssoIdKey);
        if (!StringUtils.isEmpty(ssoKey)) {
            List<String> tickets = JSON.parseArray(ssoKey, String.class);
            tickets.forEach(t -> mongoBeanUtil.getRedisTemplate().delete(TICKET_PREFIX + t));
            mongoBeanUtil.getRedisTemplate().delete(ssoKey);
        }
    }

    public void refreshRolePermission(String id) {
        Set<String> userIds = mongoBeanUtil.getSysUserRoleService().lambdaQuery().eq(SysUserRole::getRoleId, id).list().stream().map(SysUserRole::getUserId).collect(Collectors.toSet());
        if (!userIds.isEmpty()) {
            userIds.parallelStream().forEach(userId -> this.reflashTicket(userId));
        }
    }

    public void refreshPermission(String permissionId) {
        List<String> roleIds = mongoBeanUtil.getSysRolePermissionService().lambdaQuery().eq(SysRolePermission::getPermissionId, permissionId).list().stream().map(SysRolePermission::getRoleId).collect(Collectors.toList());
        if (roleIds == null || roleIds.isEmpty()) {
            return;
        }
        List<String> userIds = mongoBeanUtil.getSysUserRoleService().lambdaQuery().in(SysUserRole::getRoleId, roleIds).list().stream().map(SysUserRole::getUserId).collect(Collectors.toList());
        userIds.parallelStream().forEach(userId -> this.reflashTicket(userId));
    }


}
